package com.tanhua.admin.service;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tanhua.admin.exception.BusinessException;
import com.tanhua.admin.mapper.AnalysisMapper;
import com.tanhua.admin.mapper.LogMapper;
import com.tanhua.model.domain.Analysis;
import com.tanhua.model.vo.AnalysisSummaryVo;
import com.tanhua.model.vo.SummaryResult;
import com.tanhua.model.vo.SummaryVo;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
public class AnalysisService {

    @Autowired
    private AnalysisMapper analysisMapper;

    @Autowired
    private LogMapper logMapper;

    /**
     * 定时任务-统计日志
     * 思路：查询日志表，计算统计结果数量 ，查询当天时间段是否已经统计
     * 如果已经统计 ，修改统计数据，
     * 如果是初次统计，封装 analysis对象，添加至统计表
     * <p>
     * record_date : 统计日期
     * num_registered : 新注册用户 --- 从 Log 表中 获取 “昨天”的注册用户日志数量
     * num_active : 活跃用户数 --- 从 Log 表中 获取 活跃用户数
     * num_login : 登录次数 --- 从 Log 表中 获取 登录总数
     * num_retention1d : 次日留存用户数  --- 统计获取
     * created : 创建时间 （自动填充） ---
     * updated : 更新时间 （自动填充） ---
     */
    public void analysisLog() throws ParseException {
        //定义查询日期 不能包括具体时间
        String today = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        String yesterday = DateUtil.yesterday().toString("yyyy-MM-dd");
        //1.统计当天新注册用户数量
        Integer regCount = logMapper.countByTypeAndDate("0102", today);
        //2.统计当天用户登录数量
        Integer loginCount = logMapper.countByTypeAndDate("0101", today);
        //3.统计活跃数量
        Integer activeCount = logMapper.countActiveByDate(today);
        //4.统计次日留存
        Integer reteCount = logMapper.countRetention1dUser(today, yesterday);

        //查询当天是否统计过，
        QueryWrapper<Analysis> query = new QueryWrapper<>();
        query.eq("record_date", new SimpleDateFormat("yyyy-MM-dd").parse(today));
        Analysis analysis = analysisMapper.selectOne(query);

        if (analysis != null) {
            //如果统计过，更新
            analysis.setNumRegistered(regCount);
            analysis.setNumLogin(loginCount);
            analysis.setNumActive(activeCount);
            analysis.setNumRetention1d(reteCount);
            analysisMapper.updateById(analysis);
        } else {
            //如果为统计过直接添加
            analysis = new Analysis();
            analysis.setRecordDate(new SimpleDateFormat("yyyy-MM-dd").parse(today));
            analysis.setNumRegistered(regCount);
            analysis.setNumLogin(loginCount);
            analysis.setNumActive(activeCount);
            analysis.setNumRetention1d(reteCount);
            analysisMapper.insert(analysis);
        }
    }

    /**
     * 首页概要统计
     *
     * @return
     */
    public AnalysisSummaryVo summaryStatistics() {
        AnalysisSummaryVo analysisSumVo = new AnalysisSummaryVo();
        //1.累计用户
        Integer allUsers = analysisMapper.findAllUsers();
        Integer allUses = logMapper.summaryUserNum();
        analysisSumVo.setCumulativeUsers(Long.valueOf(allUsers));
        //今日统计信息获取
        String today = DateUtil.formatDate(new Date());
        Analysis todayAnalysis = analysisMapper.todaySummary(today);
        if (todayAnalysis == null){
            throw new BusinessException("今日还未统计，请统计后再试。");
        }
        //昨日统计信息获取
        DateTime lastDay = DateUtil.yesterday();
        String yesterday = DateUtil.formatDate(lastDay);
        Analysis lastAnalysis = analysisMapper.todaySummary(yesterday);
        if (lastAnalysis == null){
            throw new BusinessException("昨日还未统计，请统计后再试。");
        }
        //2.过去三十天活跃用户
        DateTime oneMonth = DateUtil.lastMonth();
        String lastMonth = DateUtil.formatDate(oneMonth);
        Integer activeUsers = logMapper.betweenDateActiveUser(today, lastMonth);
        analysisSumVo.setActivePassMonth(Long.valueOf(activeUsers));
        //3.过去七天活跃用户数量
        DateTime oneWeek = DateUtil.lastWeek();
        String lastWeek = DateUtil.formatDate(oneWeek);
        Integer weekActiveUsers = logMapper.betweenDateActiveUser(today, lastWeek);
        analysisSumVo.setActivePassWeek(Long.valueOf(weekActiveUsers));
        //4.今日新增用户数量
        Integer numRegistered = todayAnalysis.getNumRegistered();
        analysisSumVo.setNewUsersToday(Long.valueOf(numRegistered));
        //5.今日新增用户跌涨率，单位百度币，整数为长，负数为跌
        Integer lastNumRegistered = lastAnalysis.getNumRegistered(); //昨日注册用户数量
        //新增用户跌涨率
        BigDecimal registerRate = calculateRate(Long.valueOf(numRegistered), Long.valueOf(lastNumRegistered));
        analysisSumVo.setNewUsersTodayRate(registerRate);
        //6.今日登陆次数
        Integer numLogin = todayAnalysis.getNumLogin();
        analysisSumVo.setLoginTimesToday(Long.valueOf(numLogin));
        //7.今日登陆次数跌涨率，单位百分数，整数为涨，负数为跌
        Integer lastNumLogin = lastAnalysis.getNumLogin(); //昨日登陆次数
        //登录次数跌涨率
        BigDecimal loginRate = calculateRate(Long.valueOf(numLogin), Long.valueOf(lastNumLogin));
        analysisSumVo.setLoginTimesTodayRate(loginRate);
        //8.今日活跃用户
        Integer numActive = todayAnalysis.getNumActive();
        analysisSumVo.setActiveUsersToday(Long.valueOf(numActive));
        //9.今日活跃用户跌涨率
        Integer lastNumActive = lastAnalysis.getNumActive(); //昨日活跃用户
        //活跃次数跌涨率
        BigDecimal activeRate = calculateRate(Long.valueOf(numActive), Long.valueOf(lastNumActive));
        analysisSumVo.setActiveUsersTodayRate(activeRate);
        return analysisSumVo;
    }

    /**
     * 计算跌涨率
     *
     * @param current
     * @param last
     * @return
     */
    private static BigDecimal calculateRate(Long current, Long last) {
        BigDecimal result;
        if (last == 0) {
            // 当上一期计数为零时，此时环比增长为倍数增长
            result = new BigDecimal((current - last) * 100);
        } else {
            result = BigDecimal.valueOf((current - last) * 100).divide(BigDecimal.valueOf(last), 2,
                    BigDecimal.ROUND_HALF_DOWN);
        }
        return result;
    }

    /**
     * 统计报表
     * @param type
     * @param sd
     * @param ed
     * @return
     */
    public SummaryResult statisticalReports(String type, String sd, String ed) {
        Date startDate = new Date(Long.valueOf(sd));
        String thisStart = DateUtil.formatDate(startDate);
        Date endDate = new Date(Long.valueOf(ed));
        String thisEnd = DateUtil.formatDate(endDate);
        List<Analysis> thisYear = analysisMapper.selectBetweenAndDate(thisStart, thisEnd);
        DateTime lastStartDate = DateUtil.offset(startDate, DateField.YEAR, -1);
        String lastStart = DateUtil.formatDate(lastStartDate);
        DateTime lastEndDate = DateUtil.offset(endDate, DateField.YEAR, -1);
        String lastEnd = DateUtil.formatDate(lastEndDate);
        List<Analysis> lastYear = analysisMapper.selectBetweenAndDate(lastStart, lastEnd);
        //SummaryVo返回
        List<SummaryVo> thisSummaryVos = new ArrayList<>();
        List<SummaryVo> lastSummaryVos = new ArrayList<>();
        WrapperVoList(type, thisYear, thisSummaryVos);
        WrapperVoList(type, lastYear, lastSummaryVos);
        SummaryResult summaryResult = new SummaryResult();
        summaryResult.setThisYear(thisSummaryVos);
        summaryResult.setLastYear(lastSummaryVos);
        return summaryResult;
    }

    /**
     * 封装视图 Vo 集合
     * @param type
     * @param thisYear
     * @param summaryVos
     */
    private void WrapperVoList(String type, List<Analysis> thisYear, List<SummaryVo> summaryVos) {
        for (Analysis analysis : thisYear) {
            if (StringUtils.isNotEmpty(type) && type.equals("101")) {
                SummaryVo summaryVo = new SummaryVo();
                int dayOfMonth = DateUtil.dayOfMonth(analysis.getRecordDate());
                summaryVo.setTitle(String.valueOf(dayOfMonth));
                summaryVo.setAmount(analysis.getNumRegistered());
                summaryVos.add(summaryVo);
            } else if (StringUtils.isNotEmpty(type) && type.equals("102")) {
                SummaryVo summaryVo = new SummaryVo();
                int dayOfMonth = DateUtil.dayOfMonth(analysis.getRecordDate());
                summaryVo.setTitle(String.valueOf(dayOfMonth));
                summaryVo.setAmount(analysis.getNumActive());
                summaryVos.add(summaryVo);
            } else {
                SummaryVo summaryVo = new SummaryVo();
                int dayOfMonth = DateUtil.dayOfMonth(analysis.getRecordDate());
                summaryVo.setTitle(String.valueOf(dayOfMonth));
                summaryVo.setAmount(analysis.getNumRetention1d());
                summaryVos.add(summaryVo);
            }
        }
    }
}